#Region "Using Statements"
Imports Microsoft.Xna.Framework
Imports Microsoft.Xna.Framework.Input
#End Region

''' <summary>
''' A static encapsulation of accelerometer input to provide games with a polling-based
''' accelerometer system.
''' </summary>
Public NotInheritable Class Accelerometer
	Private Sub New()
	End Sub
	#If WINDOWS_PHONE Then
	' the accelerometer sensor on the device
	Private Shared accelerometer As New Microsoft.Devices.Sensors.Accelerometer()

	' we need an object for locking because the ReadingChanged event is fired
	' on a different thread than our game
	Private Shared threadLock As New Object()

	' we use this to keep the last known value from the accelerometer callback
	Private Shared nextValue As New Vector3()
	#End If

	' we want to prevent the Accelerometer from being initialized twice.
	Private Shared isInitialized As Boolean = False

	' whether or not the accelerometer is active
	Private Shared isActive As Boolean = False

	''' <summary>
	''' Initializes the Accelerometer for the current game. This method can only be called once per game.
	''' </summary>
	Public Shared Sub Initialize()
		' make sure we don't initialize the Accelerometer twice
		If isInitialized Then
			Throw New InvalidOperationException("Initialize can only be called once")
		End If

		#If WINDOWS_PHONE Then
		' try to start the sensor only on devices, catching the exception if it fails            
		If Microsoft.Devices.Environment.DeviceType = Microsoft.Devices.DeviceType.Device Then
			Try
				accelerometer.ReadingChanged += New EventHandler(Of Microsoft.Devices.Sensors.AccelerometerReadingEventArgs)(AddressOf sensor_ReadingChanged)
				accelerometer.Start()
				isActive = True
			Catch generatedExceptionName As Microsoft.Devices.Sensors.AccelerometerFailedException
				isActive = False
			End Try
		Else
			' we always return isActive on emulator because we use the arrow
			' keys for simulation which is always available.
			isActive = True
		End If
		#End If

		' remember that we are initialized
		isInitialized = True
	End Sub

	#If WINDOWS_PHONE Then
	Private Shared Sub sensor_ReadingChanged(sender As Object, e As Microsoft.Devices.Sensors.AccelerometerReadingEventArgs)
		' store the accelerometer value in our variable to be used on the next Update
		SyncLock threadLock
			nextValue = New Vector3(CSng(e.X), CSng(e.Y), CSng(e.Z))
		End SyncLock
	End Sub
	#End If

	''' <summary>
	''' Gets the current state of the accelerometer.
	''' </summary>
	''' <returns>A new AccelerometerState with the current state of the accelerometer.</returns>
	Public Shared Function GetState() As AccelerometerState
		' make sure we've initialized the Accelerometer before we try to get the state
		If Not isInitialized Then
			Throw New InvalidOperationException("You must Initialize before you can call GetState")
		End If

		' create a new value for our state
		Dim stateValue As New Vector3()

		#If WINDOWS_PHONE Then
		' if the accelerometer is active
		If isActive Then
			If Microsoft.Devices.Environment.DeviceType = Microsoft.Devices.DeviceType.Device Then
				' if we're on device, we'll just grab our latest reading from the accelerometer
				SyncLock threadLock
					stateValue = nextValue
				End SyncLock
			Else
				' if we're in the emulator, we'll generate a fake acceleration value using the arrow keys
				' press the pause/break key to toggle keyboard input for the emulator
				Dim keyboardState As KeyboardState = Keyboard.GetState()

				stateValue.Z = -1

				If keyboardState.IsKeyDown(Keys.Left) Then
					stateValue.X -= 1
				End If
				If keyboardState.IsKeyDown(Keys.Right) Then
					stateValue.X += 1
				End If
				If keyboardState.IsKeyDown(Keys.Up) Then
					stateValue.Y += 1
				End If
				If keyboardState.IsKeyDown(Keys.Down) Then
					stateValue.Y -= 1
				End If

				stateValue.Normalize()
			End If
		End If
		#End If

		Return New AccelerometerState(stateValue, isActive)
	End Function
End Class

''' <summary>
''' An encapsulation of the accelerometer's current state.
''' </summary>
Public Structure AccelerometerState
	''' <summary>
	''' Gets the accelerometer's current value in G-force.
	''' </summary>
	Public Property Acceleration() As Vector3
		Get
			Return m_Acceleration
		End Get
		Private Set
			m_Acceleration = Value
		End Set
	End Property
	Private m_Acceleration As Vector3

	''' <summary>
	''' Gets whether or not the accelerometer is active and running.
	''' </summary>
	Public Property IsActive() As Boolean
		Get
			Return m_IsActive
		End Get
		Private Set
			m_IsActive = Value
		End Set
	End Property
	Private m_IsActive As Boolean

	
	Public Sub New(acceleration__1 As Vector3, isActive__2 As Boolean)

		Acceleration = acceleration__1
		IsActive = isActive__2
	End Sub

	''' <summary>
	''' Returns a string containing the values of the Acceleration and IsActive properties.
	''' </summary>
	''' <returns>A new string describing the state.</returns>
	Public Overrides Function ToString() As String
		Return String.Format("Acceleration: {0}, IsActive: {1}", Acceleration, IsActive)
	End Function
End Structure
